class MyClass:
    class_attribute = "I'm a class attribute"

    def __init__(self, value):
        self.instance_attribute = value

    @classmethod
    def class_method(cls):
        print(f"Class method called. Class attribute: {cls.class_attribute}")
        # 不能访问实例属性，因为类方法没有self参数
        # print(self.instance_attribute)  # 这会报错

    def instance_method(self):
        print(f"Instance method called. Instance attribute: {self.instance_attribute}")


# 通过类调用类方法
MyClass.class_method()  # 输出: Class method called. Class attribute: I'm a class attribute

# 通过实例调用类方法
obj = MyClass("Hello")
obj.class_method()  # 输出同上

# 调用实例方法
obj.instance_method()  # 输出: Instance method called. Instance attribute: Hello


class BankAccount:
    def __init__(self, account_holder, initial_balance):
        self.account_holder = account_holder  # 公开属性
        self.__balance = initial_balance  # 私有属性（双下划线前缀）

    def deposit(self, amount):
        if amount > 0:
            self.__balance += amount
            print(f"Deposited {amount}. New balance: {self.__balance}")
        else:
            print("Deposit amount must be positive")

    def withdraw(self, amount):
        if 0 < amount <= self.__balance:
            self.__balance -= amount
            print(f"Withdrew {amount}. New balance: {self.__balance}")
        else:
            print("Invalid withdrawal amount")

    def get_balance(self):
        return self.__balance

    def __private_method(self):
        print("This is a private method")


# 创建账户
account = BankAccount("Alice", 1000)

# 访问公开属性
print(account.account_holder)  # 输出: Alice

# 尝试直接访问私有属性（实际上会被Python改名）
# print(account.__balance)     # 会报错: AttributeError
print(account._BankAccount__balance)  # 可以访问，但不推荐这样做

# 使用公共方法访问私有属性
print(account.get_balance())  # 输出: 1000

# 操作账户
account.deposit(500)  # 输出: Deposited 500. New balance: 1500
account.withdraw(200)  # 输出: Withdrew 200. New balance: 1300

# 尝试调用私有方法
# account.__private_method()   # 会报错
account._BankAccount__private_method()  # 可以调用，但不推荐


class Animal:
    def __init__(self, name):
        self.name = name
        self.__private_attr = "Secret"  # 私有属性

    def speak(self):
        raise NotImplementedError("Subclass must implement this method")

    def eat(self):
        print(f"{self.name} is eating")

    def __private_method(self):
        print("Private animal method")


class Dog(Animal):
    def __init__(self, name, breed):
        super().__init__(name)  # 调用父类的__init__
        self.breed = breed

    def speak(self):  # 重写父类方法
        print(f"{self.name} says: Woof!")

    def fetch(self):  # 子类特有方法
        print(f"{self.name} is fetching the ball")


class Cat(Animal):
    def speak(self):  # 重写父类方法
        print(f"{self.name} says: Meow!")

    def climb(self):  # 子类特有方法
        print(f"{self.name} is climbing a tree")


# 创建动物对象
dog = Dog("Buddy", "Golden Retriever")
cat = Cat("Whiskers")

# 调用继承的方法
dog.eat()  # 输出: Buddy is eating
cat.eat()  # 输出: Whiskers is eating

# 调用重写的方法
dog.speak()  # 输出: Buddy says: Woof!
cat.speak()  # 输出: Whiskers says: Meow!

# 调用子类特有方法
dog.fetch()  # 输出: Buddy is fetching the ball
cat.climb()  # 输出: Whiskers is climbing a tree

# 访问继承的属性
print(dog.name)  # 输出: Buddy
print(cat.name)  # 输出: Whiskers

# 访问子类特有属性
print(dog.breed)  # 输出: Golden Retriever

# 尝试访问私有属性
# print(dog.__private_attr)  # 会报错
# print(dog._Animal__private_attr)  # 可以访问但不推荐

# isinstance和issubclass检查
print(isinstance(dog, Animal))  # True
print(isinstance(dog, Dog))  # True
print(isinstance(dog, Cat))  # False

print(issubclass(Dog, Animal))  # True
print(issubclass(Dog, Cat))  # False


class Student:
    def __init__(self, name, age, grades):
        self.name = name
        self.age = age
        self.grades = grades  # 成绩用字典存储，如 {'math': 90, 'english': 85}

    def get_average(self):
        """计算平均成绩"""
        return sum(self.grades.values()) / len(self.grades) if self.grades else 0

    def display_info(self):
        """显示学生基本信息"""
        print(f"Student: {self.name}, Age: {self.age}")


class GraduateStudent(Student):
    def __init__(self, name, age, grades, advisor):
        # 调用父类的__init__方法初始化继承的属性
        super().__init__(name, age, grades)
        self.advisor = advisor  # 新增导师属性
        self.thesis_title = None  # 新增论文标题属性（初始为None）

    def set_thesis(self, title):
        """设置论文标题"""
        self.thesis_title = title

    def display_info(self):
        """重写父类的显示方法，增加研究生特有信息"""
        super().display_info()  # 调用父类的方法
        print(f"Advisor: {self.advisor}")
        if self.thesis_title:
            print(f"Thesis: {self.thesis_title}")

    def print_grades(self):
        """打印详细成绩单（新增方法）"""
        print(f"\nGrade Report for {self.name}:")
        for subject, grade in self.grades.items():
            print(f"{subject.capitalize()}: {grade}")
        print(f"Average: {self.get_average():.1f}")







# 创建本科生对象
undergrad = Student("Alice", 20, {'math': 88, 'english': 92, 'history': 85})
undergrad.display_info()

# 创建研究生对象
grad = GraduateStudent("Bob", 25,
                      {'math': 95, 'english': 90, 'research_methods': 88},
                      "Dr. Smith")

# 设置论文标题
grad.set_thesis("Machine Learning Applications in Biology")

# 显示研究生信息
grad.display_info()

# 打印成绩单
grad.print_grades()

# 检查继承关系
print(f"\nIs grad a Student? {isinstance(grad, Student)}")  # True
print(f"Is grad a GraduateStudent? {isinstance(grad, GraduateStudent)}")  # True
print(f"Is undergrad a GraduateStudent? {isinstance(undergrad, GraduateStudent)}")  # False


class GraduateStudent(Student):
    __minimum_gpa = 3.0  # 类私有属性（毕业最低GPA要求）

    @classmethod
    def set_minimum_gpa(cls, new_gpa):
        """类方法：修改最低GPA要求"""
        cls.__minimum_gpa = new_gpa

    def __init__(self, name, age, grades, advisor):
        super().__init__(name, age, grades)
        self.__advisor = advisor  # 私有属性
        self.__thesis_title = None

    def get_advisor(self):
        """获取导师名称（封装私有属性）"""
        return self.__advisor

    def set_thesis(self, title):
        self.__thesis_title = title

    def can_graduate(self):
        """检查是否符合毕业条件"""
        return self.get_average() >= self.__minimum_gpa

    def display_info(self):
        super().display_info()
        print(f"Advisor: {self.__advisor}")
        if self.__thesis_title:
            print(f"Thesis: {self.__thesis_title}")
        print(f"Graduation Status: {'Eligible' if self.can_graduate() else 'Not Eligible'}")


# 使用示例
phd_student = GraduateStudent("Carol", 28,
                              {'math': 95, 'research': 90, 'stats': 80},
                              "Dr. Johnson")

phd_student.set_thesis("Deep Learning in Medical Imaging")
phd_student.display_info()

# 修改类属性
GraduateStudent.set_minimum_gpa(3.5)
print(f"\nAfter changing requirement:")
phd_student.display_info()